package ldh.im.rpc.config;

import ldh.im.rpc.cache.CacheService;
import ldh.im.rpc.cache.RpcCacheService;
import ldh.im.rpc.connection.handle.RpcFilter;
import ldh.im.rpc.exception.RpcErrorCode;
import ldh.im.rpc.exception.RpcException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RpcConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(RpcConfig.class);

    private ExecutorService businessExecutorService = null;

    private List<Object> routerParamBeanList = new ArrayList<>();   // 服务端router中增加的参数
    private Map<Class, Object> beanMap = new ConcurrentHashMap();   // 代理Service
    private Map<String, RpcMapperInfo> rpcPathMap;                  // router 信息
    private Map<String, RpcMapperInfo> rpcServicePathMap;           // 代理Service信息
    private Map<Integer, List<RpcFilter>> filterMap;                //  过滤器

    private CacheService rpcCacheService = null;                    // 用户数据缓存

    private String name;

    public RpcConfig(String name) {
        this.name = name;
    }

    public RpcMapperInfo getRouter(String path) throws RpcException {
        if (!rpcPathMap.containsKey(path)) {
            throw new RpcException(RpcErrorCode.No_path, name, path);
        }
        return rpcPathMap.get(path);
    }

    public Object getRouter(Class clazz) throws RpcException {
        if (!beanMap.containsKey(clazz)) {
            try {
                Constructor constructor = clazz.getDeclaredConstructor(new Class[]{});
                Object obj =  constructor.newInstance();
                beanMap.put(clazz, obj);
                LOGGER.info("new class:{}", clazz);
                return obj;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return beanMap.get(clazz);
    }

    public RpcMapperInfo getServicePath(String path) throws RpcException {
        if (!rpcServicePathMap.containsKey(path)) {
            throw new RpcException(RpcErrorCode.No_path, getName(), path);
        }
        return rpcServicePathMap.get(path);
    }

    public String getName() {
        return this.name;
    }

    public synchronized ExecutorService getBusinessExecutorService() {
        if (businessExecutorService == null) {
            synchronized (this) {
                if (businessExecutorService == null) {
                    businessExecutorService = Executors.newVirtualThreadPerTaskExecutor();
                }
            }
        }
        return businessExecutorService;
    }

    public void close() {
        if (businessExecutorService != null) {
            businessExecutorService.shutdown();
        }
    }

    public void addRouterParamBean(Object bean) {
        routerParamBeanList.add(bean);
    }

    public Object getRouterParamBean(Class clazz) {
        for (Object obj : routerParamBeanList) {
            if (clazz.isInstance(obj)) {
                return obj;
            }
        }
        return null;
    }

    public List<RpcFilter> getAllFilters() {
        List<RpcFilter> result = new ArrayList<>();
        filterMap.entrySet().forEach(e->{
            result.addAll(e.getValue());
        });
        return result;
    }

    public RpcCacheService getRpcCacheService() {
        if (rpcCacheService instanceof RpcCacheService) {
            return (RpcCacheService) rpcCacheService;
        }
        throw new RuntimeException("缓存类有误!");
    }
}
